<?php
/**
 * @author Jumper Swordwave
 * date: 2021/04/19
 */
declare(strict_types=1);
namespace App\Game\Commands;

use Psr\Container\ContainerInterface;
use App\Constants\ErrorCode;
use App\Game\Core\{Request, Response, Command, GameStatus};
use App\Game\Service\{RoomService, UserService};
use App\Game\Task\GameTask;
use App\Game\Model\{Room, User};
use App\Log;

class GameCommand
{
    /**
     * @var ContainerInterface
     */
    private $container;

    /**
     * @var UserService
     */
    private $userService;
    
    /**
     * @var RoomService
     */
    private $roomService;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
        $this->userService = $container->get(UserService::class);
        $this->roomService = $container->get(RoomService::class);
    }

    //将用户投递到等待队列中
    private function matchRoom(User $user)
    {
        $task = $this->container->get(GameTask::class);
        $task->matchRoom($user);
    }

    /**
     * 游戏开始
     */
    public function start(Request $req)
    {
        Log::info('game start req', $req->toArray());
        $user = $this->userService->findUser($req->getFd(), $req->getUser());
        if ($user == null) {
            return Response::error(ErrorCode::USER_ERROR, '用户未登陆');
        }

        if ($user->room <= 0) { //用户不存房间内
            return $this->matchRoom($user);
        }
        $room = $this->roomService->findRoom(intval($user->room));
        if ($room == null || !$room->hasUser($user->id)) {  //房间信息已过期
            $user = $this->userService->updateUser($user, [
                'room' => 0,
                'position' => 0,
                'status' => GameStatus::USER_WAITING,
                'updated_at' => time(),
            ]);

            return $this->matchRoom($user);
        }

        $task = $this->container->get(GameTask::class);
        if ($room->status == GameStatus::ROOM_WAITING) {
            $task->userReady($room);
            return null;
        }
        
        if ($user->status == GameStatus::USER_GAMEOVER) {   //重新开始游戏
            $this->userService->ready($user);

            $task->userReady($room);
            return null;
        }

        if ($room->status == GameStatus::ROOM_CALL) {
            $task->gameCall($room);
            return null;
        }
        
        if ($room->status == GameStatus::ROOM_PLAYING) {
            $task->outCard($room);
            return null;
        }

        return null;
    }

    /**
     * 用户叫地主
     */
    public function call(Request $req)
    {
        Log::info("user call");
        $user = $this->userService->findUser($req->getFd(), $req->getUser());
        if ($user == null) {
            return Response::error(ErrorCode::USER_ERROR, '用户未登陆');
        }
        if ($user->room <= 0) {
            return Response::error(ErrorCode::ROOM_ERROR, '用户未匹配到房间');
        }
        $room = $this->roomService->findRoom(intval($user->room));
        if ($user == null || !$room->hasUser($user->id)) {
            return Response::error(ErrorCode::ROOM_ERROR, '游戏已结束');
        }

        $room = $this->roomService->gameCall($room, $user, boolval($req->input('call')));
        if ($room == null) {
            return Response::error(ErrorCode::ROOM_ERROR, '未轮到玩家叫地主');
        }

        $task = $this->container->get(GameTask::class);
        if ($room->isCallOver()) {  //叫地主结束,通知玩家结果
            $task->baseCard($room);
        } else {    //通知玩家下一位可以叫地主
            $task->gameCall($room);
        }
        return null;
    }
    
    /**
     * 用户出牌
     */
    public function outcard(Request $req)
    {
        Log::info("user out");
        $user = $this->userService->findUser($req->getFd(), $req->getUser());
        if ($user == null) {
            return Response::error(ErrorCode::USER_ERROR, '用户未登陆');
        }
        if ($user->room <= 0) {
            return Response::error(ErrorCode::ROOM_ERROR, '用户未匹配到房间');
        }
        $room = $this->roomService->findRoom(intval($user->room));
        if ($user == null || !$room->hasUser($user->id)) {
            return Response::error(ErrorCode::ROOM_ERROR, '游戏已结束');
        }

        $room = $this->roomService->outCards($room, $user, $req->input('cards'));
        if ($room != null) {    //通知玩家出牌结果
            $task = $this->container->get(GameTask::class);
            $win_id = $room->winUser();
            if ($win_id > 0) {  //玩家获胜
                $task->gameover($room);
            } else {
                $task->outCard($room);
            }
            return null;
        }
        return Response::error(ErrorCode::USER_ERROR, '出牌错误');
    }
    
}